home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Applications / NIH Image 1.60 / 1.60 Source / Edit.p < prev    next >
Encoding:
Text File  |  1996-03-01  |  55.2 KB  |  2,072 lines  |  [TEXT/PJMM]

  1. unit Edit;
  2.  
  3. {Editing routines used by NIH Image}
  4.  
  5. interface
  6.  
  7.     uses
  8.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  9.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  10.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  11.         globals, Utilities, Graphics, Camera, analysis, file1, filters, stacks, Lut, Text, math;
  12.  
  13.  
  14.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  15.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  16.     procedure Rotate (DoWhat: FlipRotateType);
  17.     procedure DoCopy;
  18.     procedure DoCut;
  19.     procedure DoPaste;
  20.     procedure DoClear;
  21.     procedure ShowClipboard;
  22.     procedure DoObject (obj: ObjectType; event: EventRecord);
  23.     procedure DoSprayCan;
  24.     procedure DoBrush (event: EventRecord);
  25.     procedure DoText (loc: point);
  26.     procedure SetSprayCanSize;
  27.     procedure SetBrushSize;
  28.     procedure SetLineWidth;
  29.     procedure UpdateEditMenu;
  30.     procedure ConverToSystemClipboard;
  31.     procedure ZoomOut;
  32.     procedure ZoomIn (event: EventRecord);
  33.     procedure Scroll (event: EventRecord);
  34.     procedure DoFill (event: EventRecord);
  35.     procedure DoGrow (WhichWindow: WindowPtr; event: EventRecord);
  36.     procedure DrawCharacter (ch: char);
  37.     procedure ConvertFromSystemClipboard;
  38.     procedure SetupOperation (item: integer);
  39.     procedure PastePicture;
  40.     procedure DoUndo;
  41.     procedure FindWhatToCopy;
  42.     procedure CopyResults;
  43.  
  44.  
  45. implementation
  46.  
  47.  
  48.     procedure PivotSelection (var SelectionRect: rect; WindowRect: rect);
  49.         var
  50.             OldWidth, NewWidth, OldHeight, NewHeight, hCenter, vCenter, NewLeft, NewTop: integer;
  51.     begin
  52.         with SelectionRect do begin
  53.                 OldWidth := right - left;
  54.                 OldHeight := bottom - top;
  55.                 hCenter := left + OldWidth div 2;
  56.                 vCenter := top + OldHeight div 2;
  57.             end;
  58.         NewWidth := OldHeight;
  59.         NewHeight := OldWidth;
  60.         NewLeft := hCenter - NewWidth div 2;
  61.         NewTop := vCenter - NewHeight div 2;
  62.         with WindowRect do begin
  63.                 if (NewLeft + NewWidth) > right then
  64.                     NewLeft := right - NewWidth;
  65.                 if (NewTop + NewHeight) > bottom then
  66.                     NewTop := bottom - NewHeight;
  67.                 if NewLeft < 0 then
  68.                     NewLeft := 0;
  69.                 if NewTop < 0 then
  70.                     NewTop := 0;
  71.             end;
  72.         with SelectionRect do begin
  73.                 left := NewLeft;
  74.                 top := NewTop;
  75.                 right := NewLeft + NewWidth;
  76.                 bottom := NewTop + NewHeight;
  77.             end;
  78.     end;
  79.  
  80.  
  81.     procedure FlipLine (var LineBuf: LineType; width: integer);
  82.         var
  83.             TempLine: LineType;
  84.             i, WidthLessOne: integer;
  85.     begin
  86.         TempLine := LineBuf;
  87.         WidthLessOne := width - 1;
  88.         for i := 0 to width - 1 do
  89.             LineBuf[i] := TempLine[WidthLessOne - i];
  90.     end;
  91.  
  92.  
  93.     procedure ScreenToOffscreenRect (var r: rect);
  94.         var
  95.             p1, p2: point;
  96.     begin
  97.         with r do begin
  98.                 p1.h := left;
  99.                 p1.v := top;
  100.                 p2.h := right;
  101.                 p2.v := bottom;
  102.                 ScreenToOffscreen(p1);
  103.                 ScreenToOffscreen(p2);
  104.                 Pt2Rect(p1, p2, r);
  105.             end;
  106.     end;
  107.  
  108.  
  109.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  110.         var
  111.             SaveInfo: InfoPtr;
  112.             width, height, hDst, vSrc, vDst, hSrc, i, inc: integer;
  113.             LineBuf: LineType;
  114.             srect, drect, MaskRect: rect;
  115.             AutoSelectAll: boolean;
  116.             SaveRow:integer;
  117.             NextUpdate: LongInt;
  118.  
  119.     begin
  120.         if NotRectangular or NotInBounds or NoUndo then
  121.             exit(FlipOrRotate);
  122.         AutoSelectAll := not Info^.RoiShowing;
  123.         if AutoSelectAll then
  124.             SelectAll(true);
  125.         if TooWide then
  126.             exit(FlipOrRotate);
  127.         ShowWatch;
  128.         SetupUndoFromClip;
  129.         SetupUndo;
  130.         if (DoWhat = RotateLeft) or (DoWhat = RotateRight) then
  131.             WhatToUndo := UndoRotate
  132.         else
  133.             WhatToUndo := UndoFlip;
  134.         SetupUndoInfoRec;
  135.         SaveInfo := Info;
  136.         srect := info^.RoiRect;
  137.         case DoWhat of
  138.  
  139.             RotateLeft, RotateRight: 
  140.                 with srect do begin
  141.                         if OptionKeyWasDown then
  142.                             DoOperation(EraseOp);
  143.                         drect := srect;
  144.                         with info^ do begin
  145.                                 PivotSelection(drect, PicRect);
  146.                                 MaskRect := drect;
  147.                                 RoiRect := drect;
  148.                                 RectRgn(roiRgn, RoiRect);
  149.                             end;
  150.                         width := right - left;
  151.                         if DoWhat = RotateLeft then begin
  152.                                 hDst := drect.left;
  153.                                 inc := 1
  154.                             end
  155.                         else begin
  156.                                 hDst := drect.right - 1;
  157.                                 inc := -1
  158.                             end;
  159.                         SaveRow:=top;
  160.                         NextUpdate:=TickCount+6; {10/sec}
  161.                         for vSrc := top to bottom - 1 do begin
  162.                                 Info := UndoInfo;
  163.                                 GetLine(left, vSrc, width, LineBuf);
  164.                                 if DoWhat = RotateLeft then
  165.                                     FlipLine(LineBuf, width);
  166.                                 Info := SaveInfo;
  167.                                 PutColumn(hDst, drect.top, width, LineBuf);
  168.                                 hDst := hDst + inc;
  169.                                 if TickCount>=NextUpdate then begin
  170.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  171.                                     UpdateScreen(MaskRect);
  172.                                     SaveRow:=vSrc+1;
  173.                                     NextUpdate:=TickCount+6;
  174.                                     ShowAnimatedWatch;
  175.                                 end;
  176.                             end;
  177.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  178.                             UpdateScreen(MaskRect);
  179.                     end;
  180.  
  181.             FlipVertical: 
  182.                 with srect do begin
  183.                         width := right - left;
  184.                         vDst := bottom;
  185.                         for vSrc := top to bottom - 1 do begin
  186.                                 Info := UndoInfo;
  187.                                 GetLine(left, vSrc, width, LineBuf);
  188.                                 Info := SaveInfo;
  189.                                 vDst := vDst - 1;
  190.                                 PutLine(left, vDst, width, LineBuf);
  191.                             end;
  192.                     end;
  193.  
  194.             FlipHorizontal: 
  195.                 with srect do begin
  196.                         width := right - left;
  197.                         SaveRow:=top;
  198.                         NextUpdate:=TickCount+6; {10/sec}
  199.                         for vSrc := top to bottom - 1 do begin
  200.                                 Info := UndoInfo;
  201.                                 GetLine(left, vSrc, width, LineBuf);
  202.                                 FlipLine(LineBuf, width);
  203.                                 Info := SaveInfo;
  204.                                 PutLine(left, vSrc, width, LineBuf);
  205.                                 if TickCount>=NextUpdate then begin
  206.                                     SetRect(MaskRect, left, SaveRow, left+width, vSrc + 1);
  207.                                     UpdateScreen(MaskRect);
  208.                                     SaveRow:=vSrc+1;
  209.                                     NextUpdate:=TickCount+6;
  210.                                     ShowAnimatedWatch;
  211.                                 end;
  212.                             end;
  213.                             SetRect(MaskRect, left, SaveRow, left+width, bottom);
  214.                             UpdateScreen(MaskRect);
  215.                     end;
  216.  
  217.         end; {case}
  218.         Info := SaveInfo;
  219.         Info^.changes := true;
  220.         SetupRoiRect;
  221.         if AutoSelectAll then
  222.             KillRoi;
  223.     end;
  224.  
  225.  
  226.  
  227.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  228.         var
  229.             SrcInfo, DstInfo: InfoPtr;
  230.             Srcwidth, DstWidth, DstHeight, hDst, vSrc, vDst, hSrc, i, inc, ignore: integer;
  231.             LineBuf: LineType;
  232.             SourceRect, DstRect, MaskRect: rect;
  233.             AutoSelectAll, isStack: boolean;
  234.             SaveCol:integer;
  235.             NextUpdate: LongInt;
  236.     begin
  237.         if NotRectangular or NotInBounds then
  238.             exit(RotateToNewWindow);
  239.         AutoSelectAll := not Info^.RoiShowing;
  240.         isStack := info^.StackInfo <> nil;
  241.         if AutoSelectAll then
  242.             SelectAll(true);
  243.         if TooWide then
  244.             exit(RotateToNewWindow);
  245.         ShowWatch;
  246.         SrcInfo := info;
  247.         with info^, info^.RoiRect do begin
  248.                 SourceRect := RoiRect;
  249.                 SrcWidth := right - left;
  250.                 DstWidth := bottom - top;
  251.                 DstHeight := right - left;
  252.                 if not NewPicWindow(title, DstWidth, DstHeight) then begin
  253.                         KillRoi;
  254.                         AbortMacro;
  255.                         exit(RotateToNewWindow)
  256.                     end;
  257.                 DstInfo := info;
  258.                 DstRect := info^.PicRect;
  259.             end;
  260.         if DoWhat = RotateLeft then begin
  261.                 hDst := 0;
  262.                 inc := 1
  263.             end
  264.         else begin
  265.                 hDst := DstWidth - 1;
  266.                 inc := -1
  267.             end;
  268.         with SourceRect do begin
  269.             SaveCol:=hDst;
  270.             NextUpdate:=TickCount+6; {10/sec}
  271.             for vSrc := top to bottom - 1 do begin
  272.                     Info := SrcInfo;
  273.                     GetLine(left, vSrc, SrcWidth, LineBuf);
  274.                     if DoWhat = RotateLeft then
  275.                         FlipLine(LineBuf, SrcWidth);
  276.                     Info := DstInfo;
  277.                     PutColumn(hDst, 0, SrcWidth, LineBuf);
  278.                     if TickCount>=NextUpdate then begin
  279.                         if DoWhat=RotateLeft
  280.                             then SetRect(MaskRect, SaveCol, 0, hDst+1, SrcWidth)
  281.                             else SetRect(MaskRect, hDst, 0, SaveCol+1, SrcWidth);
  282.                         UpdateScreen(MaskRect);
  283.                         SaveCol:=hDst+1;
  284.                         NextUpdate:=TickCount+6;
  285.                         ShowAnimatedWatch;
  286.                     end;
  287.                     hDst := hDst + inc;
  288.                 end; {for}
  289.                 if DoWhat=RotateLeft
  290.                     then SetRect(MaskRect, SaveCol, 0, dstWidth, SrcWidth)
  291.                     else SetRect(MaskRect, 0, 0, SaveCol+1, SrcWidth);
  292.                 UpdateScreen(MaskRect);
  293.             end; {with}
  294.         info^.changes := true;
  295.         if AutoSelectAll and not isStack then
  296.             with SrcInfo^ do begin
  297.                     Changes := false;
  298.                     ignore := CloseAWindow(wptr);
  299.                     info := DstInfo;
  300.                 end;
  301.     end;
  302.  
  303.  
  304.     procedure Rotate; {(DoWhat: FlipRotateType)}
  305.         const
  306.             NewWindowID = 3;
  307.         var
  308.             mylog: DialogPtr;
  309.             item: integer;
  310.             NewWindow: boolean;
  311.     begin
  312.         with info^, info^.RoiRect do
  313.             if RoiShowing then
  314.                 NewWindow := ((right - left) > PicRect.bottom) or ((bottom - top) > PicRect.right)
  315.             else begin
  316.                     RotateToNewWindow(DoWhat);
  317.                     exit(Rotate);
  318.                 end;
  319.         InitCursor;
  320.         mylog := GetNewDialog(120, nil, pointer(-1));
  321.         SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  322.         OutlineButton(MyLog, ok, 16);
  323.         repeat
  324.             if item = NewWindowID then begin
  325.                     NewWindow := not NewWindow;
  326.                     SetDlogItem(mylog, NewWindowID, ord(NewWindow));
  327.                 end;
  328.             ModalDialog(nil, item);
  329.         until (item = ok) or (item = cancel);
  330.         DisposeDialog(mylog);
  331.         if item = cancel then
  332.             exit(Rotate);
  333.         if NewWindow then
  334.             RotateToNewWindow(DoWhat)
  335.         else
  336.             FlipOrRotate(DoWhat);
  337.     end;
  338.  
  339.  
  340.     function CopyImage: boolean;
  341.         var
  342.             err, width, EvenWidth, height, size: LongInt;
  343.             line: integer;
  344.             ClipXOffset, ClipYOffset: integer;
  345.             SavePort: GrafPtr;
  346.             SaveGDevice: GDHandle;
  347.     begin
  348.         if OpPending then begin
  349.             KillRoi;
  350.             RestoreRoi;
  351.         end;
  352.         with info^, info^.RoiRect do begin
  353.             if (RoiType = RectRoi) and (PictureType = FrameGrabberType) then begin
  354.                 {We can't offset an roi copied from Camera window or "live" paste won't work}
  355.                 ClipXOffset := 0;
  356.                 ClipYOffset := 0;
  357.                 width := picRect.right;
  358.                 height := picRect.bottom;
  359.             end else begin
  360.                 ClipXOffset := left;
  361.                 ClipYOffset := top;
  362.                 width := right - left;
  363.                 height := bottom - top;
  364.             end;
  365.             if odd(width) then
  366.                 EvenWidth := width + 1
  367.             else
  368.                 EvenWidth := width;
  369.             size := EvenWidth * height;
  370.             if size > ClipBufSize then begin
  371.                 PutError(StringOf('This ',size div 1024:1,'K selection is larger than the ',ClipBufSize div 1024:1,'K Clipboard buffer.'));
  372.                 WhatsOnClip := NothingOnClip;
  373.                 AbortMacro;
  374.                 CopyImage := false;
  375.                 exit(CopyImage)
  376.             end;
  377.         end;
  378.         with ClipBufInfo^ do begin
  379.             PixelsPerLine := width;
  380.             BytesPerRow := EvenWidth;
  381.             nLines := height;
  382.             RoiRect := info^.RoiRect;
  383.             OffsetRect(RoiRect, -ClipXOffset, -ClipYOffset);
  384.             roiType := Info^.roiType;
  385.             PicRect := RoiRect;
  386.             with osPort^.portPixMap^^ do begin
  387.                     RowBytes := BitOr(BytesPerRow, $8000);
  388.                     bounds := PicRect;
  389.                 end;
  390.             with osPort^ do begin
  391.                     PortRect := PicRect;
  392.                     RectRgn(visRgn, PicRect);
  393.                 end;
  394.             if RoiType = RectRoi then begin
  395.                 if info^.PictureType = FrameGrabberType then
  396.                     WhatsOnClip := CameraPic
  397.                 else
  398.                     WhatsOnClip := RectPic
  399.             end else
  400.                 WhatsOnClip := NonRectPic;
  401.             SaveGDevice := GetGDevice;
  402.             SetGDevice(osGDevice);
  403.             GetPort(SavePort);
  404.             SetPort(GrafPtr(osPort));
  405.             CopyRgn(info^.roiRgn, roiRgn);
  406.             OffsetRgn(roiRgn, -ClipXOffset, -ClipYOffset);
  407.             ctable := info^.ctable;
  408.             pmForeColor(BlackIndex);
  409.             pmBackColor(WhiteIndex);
  410.             CopyBits(BitMapHandle(Info^.osPort^.portPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, Info^.RoiRect, RoiRect, SrcCopy, nil);
  411.             pmForeColor(ForegroundIndex);
  412.             pmBackColor(BackgroundIndex);
  413.             SetPort(SavePort);
  414.             SetGDevice(SaveGDevice);
  415.         end; {with}
  416.         CopyImage := true;
  417.     end;
  418.  
  419.  
  420.     procedure CopyWindow;
  421.         var
  422.             tPort: GrafPtr;
  423.             WindowSize: LongInt;
  424.             WindowRect: rect;
  425.             WhichWindow: WindowPtr;
  426.             kind, ignore: integer;
  427.             HidingPasteControl: boolean;
  428.             SaveGDevice: GDHandle;i:integer;
  429.     begin
  430.         WhichWindow := FrontWindow;
  431.         if WhichWindow = nil then
  432.             exit(CopyWindow);
  433.         WindowRect := WhichWindow^.PortRect;
  434.         kind := WindowPeek(WhichWindow)^.WindowKind;
  435.         HidingPasteControl := false;
  436.         with WindowRect do begin
  437.                 WindowSize := right;
  438.                 WindowSize := WindowSize * bottom;
  439.             end;
  440.         if kind = LUTKind then
  441.             WindowRect.bottom := 256;
  442.         case kind of
  443.             ProfilePlotKind:  begin
  444.                     ConvertPlotToText;
  445.                     ClipTextInBuffer := true;
  446.                 end;
  447.             CalibrationPlotKind:  begin
  448.                     ConvertCalibrationCurveToText;
  449.                     ClipTextInBuffer := true;
  450.                 end;
  451.             HistoKind, LUTKind, MapKind, ToolKind:  begin
  452.                     if PasteControl <> nil then begin
  453.                             ignore := CloseAWindow(PasteControl);
  454.                             HidingPasteControl := true;
  455.                         end;
  456.                     case kind of
  457.                         HistoKind:  begin
  458.                                 ConvertHistoToText;
  459.                                 ClipTextInBuffer := true;
  460.                                 DrawHistogram;
  461.                             end;
  462.                         MapKind: 
  463.                             DrawMap;
  464.                         LUTKind: 
  465.                             DrawLUT;
  466.                         ToolKind: 
  467.                             DrawTools;
  468.                     end; {case}
  469.                 end;
  470.             otherwise
  471.         end; {case}
  472.         if NoUndo then begin
  473.                 WhatsOnClip := NothingOnClip;
  474.                 exit(CopyWindow)
  475.             end;
  476.         ClipboardConverted := false;
  477.         with ClipBufInfo^ do begin
  478.                 RoiType := RectRoi;
  479.                 RoiRect := WindowRect;
  480.                 RectRgn(roiRgn, RoiRect);
  481.                 PicRect := WindowRect;
  482.                 PixelsPerLine := WindowRect.right;
  483.                 BytesPerRow := PixelsPerLine;
  484.                 if odd(BytesPerRow) then
  485.                     BytesPerRow := BytesPerRow + 1;
  486.                 nLines := WindowRect.bottom;
  487.                 with osPort^.portPixMap^^ do begin
  488.                         RowBytes := BitOr(BytesPerRow, $8000);
  489.                         bounds := WindowRect;
  490.                     end;
  491.                 with osPort^ do begin
  492.                         PortRect := PicRect;
  493.                         RectRgn(visRgn, PicRect);
  494.                         SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  495.                     end;
  496.                 WhatsOnClip := RectPic;
  497.                 SaveGDevice := GetGDevice;
  498.                 SetGDevice(osGDevice);
  499.                 GetPort(tPort);
  500.                 SetPort(GrafPtr(osPort));
  501.                 RGBForeColor(BlackRGB);
  502.                 RGBBackColor(WhiteRGB);
  503.                 if (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) then begin
  504.                         EraseRect(osPort^.portRect);
  505.                         DrawPlot
  506.                     end
  507.                 else
  508.                     CopyBits(WhichWindow^.PortBits, BitMapHandle(osPort^.portPixMap)^^, WindowRect, WindowRect, SrcCopy, nil);
  509.                 SetPort(tPort);
  510.                 SetGDevice(SaveGDevice);
  511.             end; {with}
  512.         if HidingPasteControl then
  513.             ShowPasteControl;
  514.     end;
  515.  
  516.  
  517.     procedure CopyResults;
  518.         var
  519.             err: OSErr;
  520.     begin
  521.         CopyResultsToBuffer(1, mCount, ShowHeadings);
  522.         UnsavedResults := false;
  523.         err := ZeroScrap;
  524.         if err = NoErr then begin
  525.                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  526.                 WhatsOnClip := NothingOnClip; {The text is on the System Scrap}
  527.             end;
  528.     end;
  529.  
  530.  
  531.     procedure DoCopy;
  532.         var
  533.             err: OSErr;
  534.     begin
  535.         err := ZeroScrap;
  536.         OldScrapCount := GetScrapCount;
  537.         case WhatToCopy of
  538.             CopyColor: 
  539.                 DoCopyColor;
  540.             CopySelection:  begin
  541.                     if not CopyImage then exit(DoCopy);
  542.                     ClipTextInBuffer := false;
  543.                     ClipboardConverted := false;
  544.                 end;
  545.             CopyHistogram, CopyPlot, CopyCalibrationPlot, CopyCLUT, CopyGrayMap, CopyTools: 
  546.                 CopyWindow;
  547.             CopyMeasurements: 
  548.                 CopyResults;
  549.             CopyText: 
  550.                 DoTextCopy;
  551.             otherwise
  552.                 beep;
  553.         end;
  554.     end;
  555.  
  556.  
  557.     procedure DoCut;
  558.     begin
  559.         DoCopy;
  560.         DoClear;
  561.     end;
  562.  
  563.  
  564.     procedure CenterRect (inRect, outRect: rect; var ResultRect: rect);
  565. {Creates a new rectangle(ResultsRect) that is the same size as inRect, but centered within outRect.}
  566.         var
  567.             width, height, hcenter, vcenter: integer;
  568.     begin
  569.         with inRect do begin
  570.                 width := right - left;
  571.                 height := bottom - top;
  572.             end;
  573.         with outRect do begin
  574.                 hcenter := left + (right - left) div 2;
  575.                 vcenter := top + (bottom - top) div 2;
  576.             end;
  577.         with ResultRect do begin
  578.                 left := hcenter - width div 2;
  579.                 top := vcenter - height div 2;
  580.                 right := left + width;
  581.                 bottom := top + height;
  582.             end;
  583.     end;
  584.  
  585.  
  586.     procedure PastePicture;
  587.         var
  588.             loc: point;
  589.             SrcWidth, SrcHeight, DstHeight, DstWidth, dh, dv: integer;
  590.             DestRect: rect;
  591.             WindowNotResized: boolean;
  592.     begin
  593.         if LivePasteMode or (PasteTransferMode <> SrcCopy) then begin
  594.                 LivePasteMode := false;
  595.                 PasteTransferMode := SrcCopy;
  596.                 if PasteControl <> nil then
  597.                     DrawPasteControl
  598.             end;
  599.         with info^ do begin
  600.                 SetupUndo;
  601.                 WhatToUndo := UndoPaste;
  602.                 if RoiShowing then
  603.                     with RoiRect do {Pasting back into selection of same size?}
  604.                         if ((right - left) = (ClipBufInfo^.RoiRect.right - ClipBufInfo^.RoiRect.left)) and ((bottom - top) = (ClipBufInfo^.RoiRect.bottom - ClipBufInfo^.RoiRect.top)) and (ClipBufInfo^.RoiType = RoiType) then begin
  605.                                 OpPending := true;
  606.                                 CurrentOp := PasteOp;
  607.                                 exit(PastePicture)
  608.                             end;
  609.                 with ClipBufInfo^.RoiRect do {Pasting into same size window?}
  610.                     if (PicRect.right = right - left) and (PicRect.bottom = (bottom - top)) and (ClipBufInfo^.RoiType = RectRoi) then begin
  611.                             SelectAll(true);
  612.                             WhatToUndo := UndoPaste;
  613.                             OpPending := true;
  614.                             CurrentOp := PasteOp;
  615.                             exit(PastePicture)
  616.                         end;
  617.                 if RoiShowing or (roiType <> NoRoi) then
  618.                     KillRoi;
  619.                 with ClipBufInfo^.RoiRect do begin
  620.                         SrcWidth := right - left;
  621.                         SrcHeight := bottom - top;
  622.                     end;
  623.                 with SrcRect do begin
  624.                         DstWidth := right - left;
  625.                         DstHeight := bottom - top;
  626.                     end;
  627.                 with initwrect do
  628.                     WindowNotResized := (DstWidth = (right - left)) and (DstHeight = (bottom - top));
  629.                 if ((SrcWidth > DstWidth) or (SrcHeight > DstHeight)) and WindowNotResized then
  630.                     DestRect := PicRect
  631.                 else
  632.                     DestRect := SrcRect;
  633.                 CenterRect(ClipBufInfo^.RoiRect, DestRect, RoiRect);
  634.                 roiType := ClipBufInfo^.roiType;
  635.                 CopyRgn(ClipBufInfo^.roiRgn, roiRgn);
  636.                 dh := RoiRect.left - roiRgn^^.rgnbbox.left;
  637.                 dv := RoiRect.top - roiRgn^^.rgnbbox.top;
  638.                 OffsetRgn(roiRgn, dh, dv);
  639.                 RoiShowing := true;
  640.                 OpPending := true;
  641.                 CurrentOp := PasteOp;
  642.                 BinaryPic := false;
  643.             end;{with}
  644.     end;
  645.  
  646.  
  647.     procedure ConvertFromSystemClipboard;
  648.   {Converts system-wide clipboard to local clipboard.}
  649.     var
  650.         phandle: handle;
  651.         offset, length, size, EvenWidth: LongInt;
  652.         pframe: rect;
  653.         width, height: LongInt;
  654.         tPort: GrafPtr;
  655.         ScrapInfo: ScrapStuffPtr;
  656.         SaveGDevice: GDHandle;
  657.     begin
  658.         ScrapInfo := InfoScrap;
  659.         if ScrapInfo^.ScrapSize <= 0 then
  660.             exit(ConvertFromSystemClipboard);
  661.         phandle := NewHandle(0);
  662.         length := GetScrap(phandle, 'PICT', offset);
  663.         if length > 0 then begin
  664.             ShowWatch;
  665.             pframe := PicHandle(phandle)^^.PicFrame;
  666.             with pframe do begin
  667.                 width := right - left;
  668.                 if odd(width) then
  669.                     EvenWidth := width + 1
  670.                 else
  671.                     EvenWidth := width;
  672.                 height := bottom - top;
  673.                 size := EvenWidth * height;
  674.                 if size > ClipBufSize then begin
  675.                     PutError(StringOf('The ', size div 1024:1,'K image on the system clipboard is too large to paste.'));
  676.                     DisposeHandle(phandle);
  677.                     exit(ConvertFromSystemClipboard)
  678.                 end;
  679.             end;
  680.             with ClipBufInfo^ do begin
  681.                 PixelsPerLine := width;
  682.                 nlines := height;
  683.                 SetRect(PicRect, 0, 0, width, height);
  684.                 RoiRect := PicRect;
  685.                 RoiType := RectRoi;
  686.                 SaveGDevice := GetGDevice;
  687.                 SetGDevice(osGDevice);
  688.                 GetPort(tPort);
  689.                 SetPort(GrafPtr(osPort));
  690.                 RectRgn(roiRgn, RoiRect);
  691.                 BytesPerRow := EvenWidth;
  692.                 with osPort^.portPixMap^^ do begin
  693.                     RowBytes := BitOr(BytesPerRow, $8000);
  694.                     bounds := PicRect;
  695.                 end;
  696.                 with CGrafPtr(osPort)^ do begin
  697.                     PortRect := PicRect;
  698.                     RectRgn(visRgn, PicRect);
  699.                     SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  700.                 end;
  701.                 RGBForecolor(WhiteRGB);
  702.                 PaintRect(PicRect);
  703.                 DrawPicture(PicHandle(phandle), PicRect);
  704.                 SetPort(tPort);
  705.                 SetGDevice(SaveGDevice);
  706.             end; {with}
  707.             WhatsOnClip := ImportedPic;
  708.         end else begin
  709.             length := GetScrap(phandle, 'TEXT', offset);
  710.             if (length > 0) and (length < MaxTextBufSize) then begin
  711.                 BlockMove(phandle^, ptr(TextBufP), length);
  712.                 TextBufSize := length;
  713.                 WhatsOnClip := TextOnClip;
  714.             end;
  715.         end;
  716.         DisposeHandle(phandle);
  717.     end;
  718.  
  719.  
  720.     procedure PasteText;
  721.         var
  722.             nTextLines, LineWidth, MaxLineWidth, MaxRectWidth, MaxRectHeight: integer;
  723.             LineStart, LineEnd, height, kind: integer;
  724.             fwptr: WindowPtr;
  725.             SaveGDevice: GDHandle;
  726.             okay: boolean;
  727.     begin
  728.         fwptr := FrontWindow;
  729.         if fwptr = nil then
  730.             exit(PasteText);
  731.         kind := WindowPeek(fwptr)^.WindowKind;
  732.         if Kind = TextKind then begin
  733.             DoTextPaste;
  734.             exit(PasteText);
  735.         end;
  736.         if TextBufSize > 5000 then begin
  737.             PutError('The maximum number of characters that can be pasted is 5000.');
  738.             exit(PasteText);
  739.         end;
  740.         if (Info = NoInfo) or NoUndo then
  741.             exit(PasteText);
  742.         with ClipBufInfo^ do begin
  743.             SaveGDevice := GetGDevice;
  744.             SetGDevice(osGDevice);
  745.             SetPort(GrafPtr(osPort));
  746.             RGBForeColor(BlackRGB);
  747.             RGBBackColor(WhiteRGB);
  748.             TextFont(CurrentFontID);
  749.             TextFace(CurrentStyle);
  750.             TextSize(CurrentSize);
  751.         end;
  752.         with info^ do if (not RoiShowing) or (RoiShowing and (RoiType <> RectRoi)) then begin
  753.             KillRoi;
  754.             nTextLines := 1;
  755.             MaxLineWidth := 10;
  756.             LineStart := 1;
  757.             LineEnd := 0;
  758.             repeat
  759.                 LineEnd := LineEnd + 1;
  760.                 if TextBufP^[LineEnd] = cr then begin
  761.                         nTextLines := nTextLines + 1;
  762.                         LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  763.                         if LineWidth > MaxLineWidth then
  764.                             MaxLineWidth := LineWidth;
  765.                         LineStart := LineEnd;
  766.                     end;
  767.             until LineEnd >= TextBufSize;
  768.             if LineEnd > LineStart then begin
  769.                     LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  770.                     if LineWidth > MaxLineWidth then
  771.                         MaxLineWidth := LineWidth;
  772.                 end;
  773.             height := nTextLines * CurrentSize + CurrentSize div 4;
  774.             MaxRectHeight := (PicRect.bottom * 2) div 3;
  775.             if height > MaxRectHeight then
  776.                 height := MaxRectHeight;
  777.             MaxLineWidth := MaxLineWidth + CurrentSize div 2;
  778.             MaxRectWidth := (PicRect.right * 2) div 3;
  779.             if MaxLineWidth > MaxRectWidth then begin
  780.                     MaxLineWidth := MaxRectWidth;
  781.                     height := MaxRectHeight;
  782.                 end;
  783.             with RoiRect do begin
  784.                     left := 0;
  785.                     top := 0;
  786.                     right := MaxLineWidth;
  787.                     bottom := height;
  788.                 end;
  789.             RoiType := RectRoi;
  790.             MakeRegion;
  791.         end;
  792.         okay := CopyImage;
  793.         if okay then begin
  794.             WhatsOnClip := TextOnClip;
  795.             SetRectRgn(ClipBufInfo^.osPort^.ClipRgn, 0, 0, 30000, 30000);  {Why is this needed?}
  796.             TETextBox(ptr(TextBufP), TextBufSize, ClipBufInfo^.RoiRect, TextJust);
  797.             PastePicture;
  798.         end;
  799.         SetGDevice(SaveGDevice);
  800.     end;
  801.  
  802.  
  803.     procedure DoPaste;
  804.         var
  805.             NewScrapCount: integer;
  806.     begin
  807.         if ((info = NoInfo) and (WhatsOnClip in [RectPic, NonRectPic, ImportedPic, CameraPic])) then begin
  808.                 if CurrentWindow <> TextKind then begin
  809.                         PutError('You must have an image window open to paste.');
  810.                         exit(DoPaste);
  811.                     end
  812.                 else
  813.                     WhatsOnClip := NothingOnClip;
  814.             end;
  815.         RoiUpdateTime := 0;
  816.         NewScrapCount := GetScrapCount;
  817.         if NewScrapCount <> OldScrapCount then begin
  818.                 WhatsOnClip := NothingOnClip;
  819.                 OldScrapCount := NewScrapCount;
  820.             end;
  821.         case WhatsOnClip of
  822.             aColor: 
  823.                 PasteColor;
  824.             RectPic, NonRectPic, ImportedPic, CameraPic: 
  825.                 PastePicture;
  826.             TextOnClip: 
  827.                 PasteText;
  828.             LivePic: 
  829.                 WhatsOnClip := NothingOnClip;
  830.             NothingOnClip:  begin
  831.                     ConvertFromSystemClipboard;
  832.                     if (WhatsOnClip = ImportedPic) and (info <> NoInfo) then
  833.                         PastePicture
  834.                     else if WhatsOnClip = textOnClip then
  835.                         PasteText
  836.                     else
  837.                         beep;
  838.                 end;
  839.         end;
  840.     end;
  841.  
  842.  
  843.     procedure DoClear;
  844.         var
  845.             fwptr: WindowPtr;
  846.             kind: integer;
  847.     begin
  848.         fwptr := FrontWindow;
  849.         if fwptr = nil then
  850.             exit(DoClear);
  851.         kind := WindowPeek(fwptr)^.WindowKind;
  852.         if Kind = TextKind then begin
  853.                 DoTextClear;
  854.                 exit(DoClear);
  855.             end;
  856.         if not NoSelection then begin
  857.                 SetupUndo;
  858.                 WhatToUndo := UndoClear;
  859.                 CurrentOp := EraseOp;
  860.                 OpPending := true;
  861.                 RoiUpdateTime := 0;
  862.             end;
  863.     end;
  864.  
  865.  
  866.     procedure ShowClipboard;
  867.         var
  868.             width, height, hstart, vstart, i, NewScrapCount: integer;
  869.             okay:boolean;
  870.     begin
  871.         NewScrapCount := GetScrapCount;
  872.         if NewScrapCount <> OldScrapCount then begin
  873.                 WhatsOnClip := NothingOnClip;
  874.                 OldScrapCount := NewScrapCount;
  875.             end;
  876.         if WhatsOnClip = NothingOnClip then
  877.             ConvertFromSystemClipboard;
  878.         if (WhatsOnClip = RectPic) or (WhatsOnClip = NonRectPic) or (WhatsOnClip = ImportedPic) or (WhatsOnClip = CameraPic) then
  879.             with ClipBufinfo^.RoiRect do begin
  880.                     width := right - left;
  881.                     height := bottom - top;
  882.                     if NewPicWindow('Clipboard', width, height) then begin
  883.                             PastePicture;
  884.                             KillRoi;
  885.                             SetupUndo;
  886.                             info^.changes := false;
  887.                         end;
  888.                 end;
  889.         if WhatsOnClip = TextOnClip then begin
  890.             if MakeNewTextWindow('Clipboard', 400, 350) then
  891.                 DoTextPaste; 
  892.         end;
  893.     end;
  894.  
  895.  
  896.     function ScreenToPixmapH (hloc: integer): extended;
  897.     begin
  898.         with info^ do
  899.             ScreenToPixmapH := SrcRect.left + hloc / magnification;
  900.     end;
  901.  
  902.     function ScreenToPixmapV (vloc: integer): extended;
  903.     begin
  904.         with info^ do
  905.             ScreenToPixmapV := SrcRect.top + vloc / magnification;
  906.     end;
  907.  
  908.  
  909.     procedure DoSelection (obj: ObjectType; start, finish: point);
  910.         var
  911.             tRect: rect;
  912.             temp, StartH, StartV, FinishH, FinishV: integer;
  913.             TempRgn: RgnHandle;
  914.     begin
  915.         WhatToUndo := NothingToUndo;
  916.         Info^.RoiShowing := false;
  917.         RoiUpdateTime := 0;
  918.         if (start.h = finish.h) or (start.v = finish.v) then
  919.             exit(DoSelection);
  920.         if start.h > finish.h then begin
  921.                 temp := start.h;
  922.                 start.h := finish.h;
  923.                 finish.h := temp;
  924.             end;
  925.         if start.v > finish.v then begin
  926.                 temp := start.v;
  927.                 start.v := finish.v;
  928.                 finish.v := temp;
  929.             end;
  930.         StartH := round(ScreenToPixmapH(start.h));
  931.         StartV := round(ScreenToPixmapV(start.v));
  932.         FinishH := round(ScreenToPixmapH(finish.h));
  933.         FinishV := round(ScreenToPixmapV(finish.v));
  934.         SetRect(tRect, StartH, StartV, FinishH, FinishV);
  935.         with info^ do begin
  936.                 RoiShowing := true;
  937.                 if SelectionMode <> NewSelection then
  938.                     TempRgn := NewRgn;
  939.                 OpenRgn;
  940.                 case obj of
  941.                     SelectionOval:  begin
  942.                             FrameOval(tRect);
  943.                             roiType := OvalRoi;
  944.                         end;
  945.                     SelectionRect:  begin
  946.                             FrameRect(tRect);
  947.                             roiType := RectRoi;
  948.                         end;
  949.                 end;
  950.                 if SelectionMode = NewSelection then
  951.                     CloseRgn(roiRgn)
  952.                 else begin
  953.                         CloseRgn(TempRgn);
  954.                         if RgnNotTooBig(roiRgn, TempRgn) then begin
  955.                                 if SelectionMode = AddSelection then
  956.                                     UnionRgn(roiRgn, TempRgn, roiRgn)
  957.                                 else begin
  958.                                         DiffRgn(roiRgn, TempRgn, roiRgn);
  959.                                         UpdatePicWindow;
  960.                                     end;
  961.                             end;
  962.                         DisposeRgn(TempRgn);
  963.                         if GetHandleSize(handle(roiRgn)) = 10 then
  964.                             roiType := RectRoi
  965.                         else
  966.                             roiType := FreehandRoi;
  967.                         nCoordinates := 0;
  968.                     end;
  969.                 RoiRect := roiRgn^^.rgnBBox;
  970.             end;{with}
  971.         measuring := false;
  972.     end;
  973.  
  974.  
  975.     procedure DoObject; {(obj: ObjectType; event: EventRecord)}
  976.         var
  977.             Start, Finish, ScreenStart, ScreenFinish, osStart, osFinish: point;
  978.             r: rect;
  979.             DeltaX, DeltaY, switch: integer;
  980.             Constrain: boolean;
  981.             StartH, StartV: extended;
  982.     begin
  983.         SetPort(info^.wptr);
  984.         if obj = LineObj then
  985.             DrawLabels('DX:', 'DY:', 'Length:')
  986.         else
  987.             DrawLabels('Width:', 'Height:', '');
  988.         start := event.where;
  989.         StartH := ScreenToPixmapH(start.h);
  990.         StartV := ScreenToPixmapV(start.v);
  991.         osStart := start;
  992.         ScreenToOffscreen(osStart);
  993.         finish := start;
  994.         osFinish := finish;
  995.         ScreenToOffscreen(osFinish);
  996.         PenNormal;
  997.         PenMode(PatXor);
  998.         PenSize(1, 1);
  999.         while button do begin
  1000.                 GetMouse(finish);
  1001.                 with finish, Info^ do begin
  1002.                         if h > wrect.right then
  1003.                             h := wrect.right;
  1004.                         if v > wrect.bottom then
  1005.                             v := wrect.bottom;
  1006.                         if h < 0 then
  1007.                             h := 0;
  1008.                         if v < 0 then
  1009.                             v := 0;
  1010.                     end;
  1011.                 if ShiftKeyDown then begin
  1012.                         DeltaX := finish.h - start.h;
  1013.                         DeltaY := finish.v - start.v;
  1014.                         if obj = lineObj then begin
  1015.                                 if abs(DeltaX) > abs(DeltaY) then
  1016.                                     finish.v := start.v
  1017.                                 else
  1018.                                     finish.h := start.h
  1019.                             end
  1020.                         else begin
  1021.                                 if ((DeltaX > 0) and (DeltaY < 0)) or ((DeltaX < 0) and (DeltaY > 0)) then
  1022.                                     switch := -1
  1023.                                 else
  1024.                                     switch := 1;
  1025.                                 if abs(DeltaX) > abs(DeltaY) then
  1026.                                     finish.h := start.h + switch * DeltaY
  1027.                                 else
  1028.                                     finish.v := start.v + switch * DeltaX;
  1029.                             end;
  1030.                     end;
  1031.                 osFinish := finish;
  1032.                 ScreenToOffscreen(osfinish);
  1033.                 case obj of
  1034.                     LineObj:  begin
  1035.                             MoveTo(start.h, start.v);
  1036.                             LineTo(finish.h, finish.v);
  1037.                             ShowDxDy(abs(ScreenToPixMapH(finish.h) - StartH), abs(ScreenToPixMapV(finish.v) - StartV));
  1038.                             MoveTo(start.h, start.v);
  1039.                             LineTo(finish.h, finish.v);
  1040.                         end;
  1041.                     Rectangle, SelectionRect:  begin
  1042.                             if obj = SelectionRect then begin
  1043.                                     PatIndex := (PatIndex + 1) mod 8;
  1044.                                     PenPat(AntPattern[PatIndex]);
  1045.                                 end;
  1046.                             Pt2Rect(start, finish, r);
  1047.                             FrameRect(r);
  1048.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1049.                             Pt2Rect(start, finish, r);
  1050.                             FrameRect(r);
  1051.                         end;
  1052.                     SelectionOval:  begin
  1053.                             PatIndex := (PatIndex + 1) mod 8;
  1054.                             PenPat(AntPattern[PatIndex]);
  1055.                             Pt2Rect(start, finish, r);
  1056.                             FrameOval(r);
  1057.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1058.                             Pt2Rect(start, finish, r);
  1059.                             FrameOval(r);
  1060.                         end;
  1061.                 end; {case}
  1062.             end;  {while button}
  1063.         if (obj = SelectionRect) or (obj = SelectionOval) then begin
  1064.                 DoSelection(obj, start, finish);
  1065.                 exit(DoObject);
  1066.             end;
  1067.         if (obj = LineObj) and ((CurrentTool = LineTool) or (CurrentTool = PlotTool)) then begin
  1068.                 MoveTo(start.h, start.v);
  1069.                 LineTo(finish.h, finish.v);
  1070.                 with info^ do begin
  1071.                         LX1 := StartH;
  1072.                         LY1 := StartV;
  1073.                         LX2 := ScreenToPixmapH(finish.h);
  1074.                         LY2 := ScreenToPixmapV(finish.v);
  1075.                         if LX1 > (PicRect.right - 1) then
  1076.                             LX1 := PicRect.right - 1;
  1077.                         if LY1 > (PicRect.bottom - 1) then
  1078.                             LY1 := PicRect.bottom - 1;
  1079.                         if LX1 < 0 then
  1080.                             LX1 := 0;
  1081.                         if LY1 < 0 then
  1082.                             LY1 := 0;
  1083.                         if LX2 > (PicRect.right - 1) then
  1084.                             LX2 := PicRect.right - 1;
  1085.                         if LY2 > (PicRect.bottom - 1) then
  1086.                             LY2 := PicRect.bottom - 1;
  1087.                         if LX2 < 0 then
  1088.                             LX2 := 0;
  1089.                         if LY2 < 0 then
  1090.                             LY2 := 0;
  1091.                     end;
  1092.                 exit(DoObject);
  1093.             end;
  1094.         DrawObject(obj, start, finish);
  1095.     end;
  1096.  
  1097.  
  1098.     procedure DrawSprayCan (xcenter, ycenter: integer);
  1099.         var
  1100.             i, xoffset, yoffset, nDots: LongInt;
  1101.     begin
  1102.         nDots := SprayCanDiameter div 4;
  1103.         if nDots < 15 then
  1104.             nDots := 15;
  1105.         for i := 1 to nDots do begin
  1106.                 repeat
  1107.                     xoffset := random mod SprayCanRadius;
  1108.                     yoffset := random mod SprayCanRadius;
  1109.                 until xoffset * xoffset + yoffset * yoffset <= SprayCanRadius2;
  1110.                 PutPixel(xcenter + xoffset, ycenter + yoffset, ForegroundIndex);
  1111.             end;
  1112.     end;
  1113.  
  1114.  
  1115.     procedure DoSprayCan;
  1116.   {Reference: "Spaying and Smudging", Dick Pountain, Byte, November 1987}
  1117.         var
  1118.             xcenter, ycenter, off: integer;
  1119.             MaskRect: rect;
  1120.             pt: point;
  1121.             SaveTicks:LongInt;
  1122.     begin
  1123.         info^.changes := true;
  1124.         off := SprayCanRadius;
  1125.         SaveTicks:=TickCount;
  1126.         repeat
  1127.             repeat until TickCount<>SaveTicks; {Update no more than 60 times per second}
  1128.             SaveTicks:=TickCount;
  1129.             GetMouse(pt);
  1130.             ScreenToOffscreen(pt);
  1131.             with MaskRect, pt do begin
  1132.                     left := h - off;
  1133.                     top := v - off;
  1134.                     right := h + off;
  1135.                     bottom := v + off;
  1136.                 end;
  1137.             with pt do begin
  1138.                     xcenter := h;
  1139.                     ycenter := v
  1140.                 end;
  1141.             DrawSprayCan(xcenter, ycenter);
  1142.             UpdateScreen(MaskRect);
  1143.         until not button;
  1144.         WhatToUndo := UndoEdit;
  1145.     end;
  1146.  
  1147.  
  1148.     procedure DoBrush; {(event: EventRecord)}
  1149.         var
  1150.             r, ScreenRect: rect;
  1151.             p1, p2, p2x, start: point;
  1152.             WhichWindow: WindowPtr;
  1153.             SaveLineWidth, SaveForegroundColor: integer;
  1154.             Constrained, MoreHorizontal, FirstTime: boolean;
  1155.             offset, width: integer;
  1156.             rWidth: double;
  1157.     begin
  1158.         SaveLineWidth := LineWidth;
  1159.         p1 := event.where;
  1160.         start := p1;
  1161.         if OptionKeyDown then begin
  1162.                 case CurrentTool of
  1163.                     Brush, Pencil: 
  1164.                         GetForegroundColor(event);
  1165.                     Eraser: 
  1166.                         GetBackgroundColor(event);
  1167.                 end;
  1168.                 if (CurrentTool = Brush) or (CurrentTool = Eraser) then
  1169.                     exit(DoBrush);
  1170.             end;
  1171.         case CurrentTool of
  1172.             Pencil: 
  1173.                 LineWidth := 1;
  1174.             Brush, Eraser:  begin
  1175.                     if CurrentTool = Brush then
  1176.                         width := BrushWidth
  1177.                     else
  1178.                         width := 16;
  1179.                     LineWidth := round(width / info^.magnification);
  1180.                     if LineWidth < 1 then
  1181.                         LineWidth := 1;
  1182.                 end;
  1183.         end;
  1184.         with info^ do
  1185.             rWidth := (LineWidth - 1) * info^.magnification / 2.0;
  1186.             offset := round(rWidth * 1.00000001);  {ppc-bug}
  1187.         if CurrentTool <> Pencil then
  1188.             with p1 do begin
  1189.                     h := h - offset;
  1190.                     v := v - offset
  1191.                 end;
  1192.         Constrained := ShiftKeyDown;
  1193.         FirstTime := true;
  1194.         if CurrentTool = eraser then begin
  1195.                 SaveForegroundColor := ForegroundIndex;
  1196.                 SetForegroundColor(BackgroundIndex)
  1197.             end;
  1198.         repeat
  1199.             GetMouse(p2);
  1200.             if CurrentTool <> Pencil then
  1201.                 with p2 do begin
  1202.                         h := h - offset;
  1203.                         v := v - offset
  1204.                     end;
  1205.             if FirstTime then
  1206.                 if not EqualPt(p1, p2) then begin
  1207.                         MoreHorizontal := abs(p2.h - p1.h) >= abs(p2.v - p1.v);
  1208.                         FirstTime := false;
  1209.                     end;
  1210.             if Constrained then
  1211.                 if MoreHorizontal then
  1212.                     p2.v := p1.v
  1213.                 else
  1214.                     p2.h := p1.h;
  1215.             if CurrentTool = brush then
  1216.                 DrawObject(BrushObj, p1, p2)
  1217.             else
  1218.                 DrawObject(LineObj, p1, p2);
  1219.             p1 := p2;
  1220.         until not button;
  1221.         if CurrentTool = Eraser then
  1222.             SetForegroundColor(SaveForegroundColor);
  1223.         LineWidth := SaveLineWidth;
  1224.         WhatToUndo := UndoEdit;
  1225.     end;
  1226.  
  1227.  
  1228.     procedure DrawCharacter; {(ch: char)}
  1229.         var
  1230.             str: str255;
  1231.     begin
  1232.         if Info = NoInfo then begin
  1233.                 beep;
  1234.                 exit(DrawCharacter)
  1235.             end;
  1236.         if ch = cr then
  1237.             with InsertionPoint do begin
  1238.                     h := TextStart.h;
  1239.                     v := v + CurrentSize;
  1240.                     SetupUndo;
  1241.                     TextStr := '';
  1242.                     TextStart := InsertionPoint;
  1243.                     exit(DrawCharacter)
  1244.                 end;
  1245.         if ch = BackSpace then
  1246.             with InsertionPoint do begin
  1247.                     if length(TextStr) > 0 then begin
  1248.                             delete(TextStr, length(TextStr), 1);
  1249.                             DisplayText(true);
  1250.                         end;
  1251.                     exit(DrawCharacter)
  1252.                 end;
  1253.         str := ' '; {Needed for MPW}
  1254.         str[1] := ch;
  1255.         TextStr := Concat(TextStr, str);
  1256.         DisplayText(true);
  1257.     end;
  1258.  
  1259.  
  1260.     procedure DoText; {(loc: point)}
  1261.   {Handles text tool mouse clicks.}
  1262.         var
  1263.             value: extended;
  1264.             str: str255;
  1265.             isValue: boolean;
  1266.     begin
  1267.         if NoUndo then
  1268.             exit(DoText);
  1269.         ScreenToOffscreen(loc);
  1270.         with loc do begin
  1271.                 InsertionPoint.h := h;
  1272.                 InsertionPoint.v := v + 4;
  1273.             end;
  1274.         IsInsertionPoint := true;
  1275.         TextStart := InsertionPoint;
  1276.         TextStr := '';
  1277.         if OptionKeyDown then
  1278.             with info^ do begin
  1279.                     isValue := true;
  1280.                     if (PreviousTool = LineTool) and (nLengths > 0) then
  1281.                         value := plength^[mCount2]
  1282.                     else if (PreviousTool = AngleTool) and (nAngles > 0) then
  1283.                         value := orientation^[mCount2]
  1284.                     else if mCount > 0 then
  1285.                         if AreaM in Measurements then
  1286.                             value := mArea^[mCount2]
  1287.                         else if MeanM in Measurements then
  1288.                             value := mean^[mCount2]
  1289.                         else
  1290.                             isValue := false;
  1291.                     if isValue then begin
  1292.                             RealToString(value, 1, precision, str);
  1293.                             if mCount2 > 0 then
  1294.                                 mCount2 := mCount2 - 1;
  1295.                             DrawTextString(str, TextStart, TextJust);
  1296.                         end;
  1297.                 end;
  1298.         WhatToUndo := UndoEdit;
  1299.     end;
  1300.  
  1301.  
  1302.     procedure DoFill (event: EventRecord);
  1303.         var
  1304.             loc: point;
  1305.             MaskBits: BitMap;
  1306.             BitMapSize: LongInt;
  1307.             tPort: GrafPtr;
  1308.             trect: rect;
  1309.             SaveGDevice: GDHandle;
  1310.     begin
  1311.         ShowWatch;
  1312.         loc := event.where;
  1313.         ScreenToOffscreen(loc);
  1314.         with info^ do begin
  1315.                 tRect := PicRect;
  1316.                 with tRect do
  1317.                     if (right mod 16 <> 0) and not Has32BitQuickDraw then
  1318.                         right := (right div 16) * 16 + 16;  {Workaround for SeedCFill bug that results in  garbage along right edge.}
  1319.                 with MaskBits do begin
  1320.                         RowBytes := PixelsPerLine div 8 + 1;
  1321.                         if odd(RowBytes) then
  1322.                             RowBytes := RowBytes + 1;
  1323.                         bounds := tRect;
  1324.                         BitMapSize := rowBytes * nLines;
  1325.                         baseAddr := NewPtr(BitMapSize);
  1326.                         if baseAddr = nil then begin
  1327.                                 beep;
  1328.                                 exit(DoFill)
  1329.                             end;
  1330.                     end;
  1331.                 SaveGDevice := GetGDevice;
  1332.                 SetGDevice(osGDevice);
  1333.                 GetPort(tPort);
  1334.                 SetPort(GrafPtr(osPort));
  1335.                 pmForeColor(ForegroundIndex);
  1336.                 SeedCFill(BitMapHandle(osPort^.PortPixMap)^^, MaskBits, tRect, tRect, loc.h, loc.v, nil, 0);
  1337.                 CopyBits(MaskBits, BitMapHandle(osPort^.PortPixMap)^^, tRect, tRect, SrcOr, nil);
  1338.                 DisposePtr(MaskBits.baseAddr);
  1339.                 changes := true;
  1340.             end; {with}
  1341.         SetPort(tPort);
  1342.         SetGDevice(SaveGDevice);
  1343.         UpdatePicWindow;
  1344.         WhatToUndo := UndoEdit;
  1345.     end;
  1346.  
  1347.  
  1348.     procedure SetSprayCanSize;
  1349.         var
  1350.             TempSize: integer;
  1351.             Canceled: boolean;
  1352.     begin
  1353.         TempSize := GetInt('Spray can diameter in pixels(2-250):', SprayCanDiameter, Canceled);
  1354.         if Canceled then
  1355.             exit(SetSprayCanSize);
  1356.         if (TempSize > 1) and (TempSize <= 250) then begin
  1357.                 SprayCanDiameter := TempSize;
  1358.                 SprayCanRadius := SprayCanDiameter div 2;
  1359.                 SprayCanRadius2 := SprayCanRadius * SprayCanRadius
  1360.             end
  1361.         else
  1362.             beep;
  1363.     end;
  1364.  
  1365.  
  1366.     procedure SetBrushSize;
  1367.         var
  1368.             TempSize: integer;
  1369.             Canceled: boolean;
  1370.             i, ticks, x, y: LongInt;
  1371.             v: integer;
  1372.     begin
  1373.         TempSize := GetInt('Brush Size in pixels(1..99):', BrushWidth, Canceled);
  1374.         if Canceled then
  1375.             exit(SetBrushSize);
  1376.         if (TempSize > 0) and (TempSize < 100) then begin
  1377.                 BrushWidth := TempSize;
  1378.                 BrushHeight := BrushWidth
  1379.             end
  1380.         else
  1381.             beep;
  1382. {exit(SetBrushSize);}
  1383.     {Timer}
  1384.         x := 100;
  1385.         y := 100;
  1386.         ticks := TickCount;
  1387.         for i := 1 to 1000000 do
  1388.             v := MyGetPixel(x, y);
  1389.         ShowMessage(concat('ticks=', long2str(TickCount - ticks)));
  1390.     end;
  1391.  
  1392.  
  1393.     procedure SetLineWidth;
  1394.         var
  1395.             TempSize: integer;
  1396.             Canceled: boolean;
  1397.     begin
  1398.         TempSize := GetInt('Line Width in pixels(1..100):', LineWidth, Canceled);
  1399.         if Canceled then
  1400.             exit(SetLineWidth);
  1401.         if (TempSize > 0) and (TempSize <= 100) then begin
  1402.                 LineWidth := TempSize;
  1403.                 ShowLineWidth;
  1404.             end
  1405.         else
  1406.             beep;
  1407.     end;
  1408.  
  1409.  
  1410.     procedure FindWhatToCopy;
  1411.         var
  1412.             kind: integer;
  1413.             WhichWindow: WindowPtr;
  1414.     begin
  1415.         WhatToCopy := NothingToCopy;
  1416.         WhichWindow := FrontWindow;
  1417.         if WhichWindow = nil then
  1418.             exit(FindWhatToCopy);
  1419.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1420.         if (CurrentTool = PickerTool) and (kind <> TextKind) then
  1421.             WhatToCopy := CopyColor
  1422.         else begin
  1423.                 if (kind = PicKind) and measuring and (not macro) then
  1424.                     kind := ResultsKind;
  1425.                 case kind of
  1426.                     PicKind: 
  1427.                         with info^, info^.RoiRect do
  1428.                             if RoiShowing and (left >= 0) and (top >= 0) and (right <= PicRect.right) and (bottom <= PicRect.bottom) then
  1429.                                 WhatToCopy := CopySelection;
  1430.                     HistoKind: 
  1431.                         WhatToCopy := CopyHistogram;
  1432.                     ProfilePlotKind: 
  1433.                         WhatToCopy := CopyPlot;
  1434.                     CalibrationPlotKind: 
  1435.                         WhatToCopy := CopyCalibrationPlot;
  1436.                     LUTKind: 
  1437.                         if info <> NoInfo then
  1438.                             WhatToCopy := CopyCLUT;
  1439.                     MapKind: 
  1440.                         if info <> NoInfo then
  1441.                             WhatToCopy := CopyGrayMap;
  1442.                     ToolKind: 
  1443.                         WhatToCopy := CopyTools;
  1444.                     TextKind:  begin
  1445.                             TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1446.                             if TextInfo <> nil then
  1447.                                 with TextInfo^.TextTE^^ do
  1448.                                     if selEnd > selStart then
  1449.                                         WhatToCopy := CopyText;
  1450.                         end;
  1451.                     InfoKind, ResultsKind: 
  1452.                         if mCount > 0 then
  1453.                             WhatToCopy := CopyMeasurements;
  1454.                     otherwise
  1455.                 end;
  1456.             end;
  1457.     end;
  1458.  
  1459.  
  1460.     procedure UpdateEditMenu;
  1461.         var
  1462.             DimUndo, ShowItems: boolean;
  1463.             str: str255;
  1464.             i: integer;
  1465.     begin
  1466.         with info^ do begin
  1467.                 if CurrentKind < 0 then begin   {DA is active, so activate Edit menu.}
  1468.                         SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1469.                         SetMenuItemText(EditMenuH, CutItem, 'Cut');
  1470.                         SetMenuItemText(EditMenuH, CopyItem, 'Copy');
  1471.                         SetMenuItem(EditMenuH, UndoItem, true);
  1472.                         for i := CutItem to ClearItem do
  1473.                             SetMenuItem(EditMenuH, i, true);
  1474.                         exit(UpdateEditMenu);
  1475.                     end;
  1476.                 if not (WhatToUndo in [UndoLUT, UndoMeasurement, UndoPoint]) and ((info = NoInfo) or (PixMapSize <> CurrentUndoSize)) then
  1477.                     WhatToUndo := NothingToUndo;
  1478.                 DimUndo := WhatToUndo = NothingToUndo;
  1479.                 SetMenuItem(EditMenuH, UndoItem, not DimUndo);
  1480.                 if DimUndo then
  1481.                     SetMenuItemText(EditMenuH, UndoItem, 'Undo');
  1482.                 case WhatToUndo of
  1483.                     UndoEdit: 
  1484.                         str := 'Editing';
  1485.                     UndoFlip: 
  1486.                         str := 'Flip';
  1487.                     UndoRotate: 
  1488.                         str := 'Rotate';
  1489.                     UndoFilter: 
  1490.                         str := 'Filtering';
  1491.                     UndoPaste: 
  1492.                         str := 'Paste';
  1493.                     UndoMeasurement, UndoPoint: 
  1494.                         str := 'Measurement';
  1495.                     UndoTransform: 
  1496.                         str := 'Transformation';
  1497.                     UndoClear: 
  1498.                         str := 'Clear';
  1499.                     UndoZoom: 
  1500.                         str := 'Zoom';
  1501.                     UndoOutline: 
  1502.                         str := 'Outline';
  1503.                     UndoSliceDelete, UndoFirstSliceDelete: 
  1504.                         str := 'Delete Slice';
  1505.                     UndoLUT: 
  1506.                         str := 'LUT Change';
  1507.                     otherwise
  1508.                         str := '';
  1509.                 end;
  1510.                 SetMenuItemText(EditMenuH, UndoItem, concat('Undo ', str));
  1511.                 FindWhatToCopy;
  1512.                 if WhatToCopy = CopySelection then
  1513.                     str := 'Cut Selection'
  1514.                 else
  1515.                     str := 'Cut';
  1516.                 SetMenuItemText(EditMenuH, CutItem, str);
  1517.                 SetMenuItem(EditMenuH, CutItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1518.                 case WhatToCopy of
  1519.                     NothingToCopy, CopyText: 
  1520.                         str := '';
  1521.                     CopySelection: 
  1522.                         str := 'Selection';
  1523.                     CopyCLUT: 
  1524.                         str := 'LUT';
  1525.                     CopyGrayMap: 
  1526.                         str := 'Gray Map';
  1527.                     CopyTools: 
  1528.                         str := 'Tools';
  1529.                     CopyPlot: 
  1530.                         str := 'Plot';
  1531.                     CopyCalibrationPlot: 
  1532.                         str := 'Calibration Plot';
  1533.                     CopyHistogram: 
  1534.                         str := 'Histogram';
  1535.                     CopyMeasurements: 
  1536.                         str := 'Measurements';
  1537.                     CopyColor: 
  1538.                         str := 'Color';
  1539.                 end;
  1540.                 SetMenuItemText(EditMenuH, CopyItem, concat('Copy ', str));
  1541.                 SetMenuItem(EditMenuH, CopyItem, WhatToCopy <> NothingToCopy);
  1542.                 SetMenuItem(EditMenuH, ClearItem, (WhatToCopy = CopySelection) or (WhatToCopy = CopyText));
  1543.                 ShowItems := (WhatsOnClip <> NothingOnClip) or (OldScrapCount <> GetScrapCount);
  1544.                 SetMenuItem(EditMenuH, PasteItem, ShowItems);
  1545.                 SetMenuItem(EditMenuH, ShowClipboardItem, ShowItems);
  1546.                 ShowItems := info <> NoInfo;
  1547.                 if CurrentKind = TextKind then
  1548.                     SetMenuItemText(EditMenuH, FillItem, 'Find…')
  1549.                 else
  1550.                     SetMenuItemText(EditMenuH, FillItem, 'Fill');
  1551.                 SetMenuItem(EditMenuH, FillItem, ShowItems or (CurrentKind = TextKind));
  1552.                 SetMenuItem(EditMenuH, InvertItem, ShowItems);
  1553.                 SetMenuItem(EditMenuH, DrawBoundaryItem, ShowItems);
  1554.                 SetMenuItem(EditMenuH, DrawScaleItem, ShowItems);
  1555.                 if (RoiShowing and EqualRect(RoiRect, PicRect)) and (CurrentKind <> TextKind) then
  1556.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Deselect All')
  1557.                 else
  1558.                     SetMenuItemText(EditMenuH, SelectAllItem, 'Select All');
  1559.                 SetMenuItem(EditMenuH, SelectAllItem, ShowItems or (CurrentKind = TextKind));
  1560.                 SetMenuItem(EditMenuH, DeselectItem, ShowItems and RoiShowing);
  1561.                 SetMenuItem(EditMenuH, ScaleAndRotateItem, ShowItems);
  1562.                 for i := RotateLeftItem to FlipHorizontalItem do
  1563.                     SetMenuItem(EditMenuH, i, ShowItems);
  1564.                 SetMenuItem(EditMenuH, UnZoomItem, ShowItems and ((magnification <> 1.0) or ScaleToFitWindow));
  1565.             end; {with}
  1566.     end;
  1567.  
  1568.  
  1569.     procedure ZoomOut;
  1570.         var
  1571.             Width, Height, divisor, NewWidth, NewHeight: integer;
  1572.             OldMagnification, xratio, yratio: extended;
  1573.     begin
  1574.         with Info^ do begin
  1575.                 if magnification < 2.0 then begin
  1576.                         beep;
  1577.                         exit(ZoomOut)
  1578.                     end;
  1579.                 OldMagnification := magnification;
  1580.                 if magnification = 2.0 then begin
  1581.                         magnification := 1.0;
  1582.                         divisor := 4
  1583.                     end
  1584.                 else if magnification = 3.0 then begin
  1585.                         magnification := 2.0;
  1586.                         divisor := 6
  1587.                     end
  1588.                 else if magnification = 4.0 then begin
  1589.                         magnification := 3.0;
  1590.                         divisor := 8
  1591.                     end
  1592.                 else begin
  1593.                         magnification := magnification / 2.0;
  1594.                         divisor := 4
  1595.                     end;
  1596.                 if EqualRect(SrcRect, PicRect) then begin {Make window smaller}
  1597.                         NewWidth := trunc(PicRect.right * magnification);
  1598.                         NewHeight := trunc(PicRect.bottom * magnification);
  1599.                         SizeWindow(wptr, NewWidth, NewHeight, true);
  1600.                         wrect.right := NewWidth;
  1601.                         wrect.bottom := NewHeight;
  1602.                         SrcRect := PicRect;
  1603.                         UpdateTitleBar;
  1604.                         UpdatePicWindow;
  1605.                         DrawMyGrowIcon(wptr);
  1606.                         exit(ZoomOut);
  1607.                     end;
  1608.                 if ((wrect.right > PicRect.right) or (wrect.bottom > PicRect.bottom)) then begin
  1609.                         xratio := wrect.right / PicRect.right;
  1610.                         yratio := wrect.bottom / PicRect.bottom;
  1611.                         if (xratio <> yratio) or ((xratio - trunc(xratio)) <> 0.0) then begin
  1612.                                 UnZoom;
  1613.                                 Exit(ZoomOut)
  1614.                             end;
  1615.                         SrcRect := PicRect;
  1616.                         Magnification := xratio;
  1617.                         UpdateTitleBar;
  1618.                         UpdatePicWindow;
  1619.                         DrawMyGrowIcon(wptr);
  1620.                         Exit(ZoomOut)
  1621.                     end;
  1622.             end; {with}
  1623.         with Info^.SrcRect, info^ do begin
  1624.                 if magnification = 1.0 then begin
  1625.                         width := wrect.right;
  1626.                         height := wrect.bottom;
  1627.                     end
  1628.                 else begin
  1629.                         width := round((right - left) * OldMagnification / Magnification);
  1630.                         height := round((bottom - top) * OldMagnification / Magnification);
  1631.                     end;
  1632.                 left := left - (width div divisor);
  1633.                 if left < 0 then
  1634.                     left := 0;
  1635.                 if (left + width) > Info^.PicRect.right then
  1636.                     left := Info^.PicRect.right - width;
  1637.                 top := top - (height div divisor);
  1638.                 if top < 0 then
  1639.                     top := 0;
  1640.                 if (top + height) > Info^.PicRect.bottom then
  1641.                     top := Info^.picRect.bottom - height;
  1642.                 right := left + width;
  1643.                 bottom := top + height;
  1644.                 RoiShowing := false;
  1645.                 UpdatePicWindow;
  1646.                 DrawMyGrowIcon(wptr);
  1647.                 UpdateTitleBar;
  1648.             end;
  1649.         ShowRoi;
  1650.     end;
  1651.  
  1652.  
  1653.     procedure DoGrow; {(WhichWindow: WindowPtr; event: EventRecord)}
  1654.         var
  1655.             NewSize: LongInt;
  1656.             trect, WinRect, SizeRect: rect;
  1657.             kind: integer;
  1658.             WasDigitizing: boolean;
  1659.             ZoomCenterH, ZoomCenterV, width, height: extended;
  1660.     begin
  1661.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1662.         if kind = PicKind then
  1663.             with info^, SizeRect do begin
  1664.                     if ScaleToFitWindow then
  1665.                         SizeRect := qd.ScreenBits.bounds
  1666.                     else begin
  1667.                             right := PicRect.right + 1;
  1668.                             bottom := PicRect.bottom + 1;
  1669.                             if magnification > 1.0 then begin
  1670.                                     right := round(right * magnification);
  1671.                                     bottom := round(bottom * magnification);
  1672.                                 end;
  1673.                             left := 32;
  1674.                             top := 32;
  1675.                             if left > right then
  1676.                                 left := right;
  1677.                             if top > bottom then
  1678.                                 top := bottom;
  1679.                         end
  1680.                 end
  1681.         else
  1682.             SetRect(SizeRect, 64, 48, 2048, 2048);
  1683.         NewSize := GrowWindow(WhichWindow, event.where, SizeRect);
  1684.         if newSize = 0 then
  1685.             exit(DoGrow);
  1686.         if kind = PicKind then
  1687.             with Info^ do begin
  1688.                     SetPort(wptr);
  1689.                     WasDigitizing := digitizing;
  1690.                     StopDigitizing;
  1691.                     InvalRect(wrect);
  1692.                     with trect do begin
  1693.                             top := 0;
  1694.                             left := 0;
  1695.                             right := LoWrd(NewSize);
  1696.                             bottom := HiWrd(NewSize);
  1697.                         end;
  1698.                     if ScaleToFitWindow then begin
  1699.                             ScaleImageWindow(trect);
  1700.                             wrect := trect;
  1701.                         end
  1702.                     else begin
  1703.                             if trect.right > PicRect.right * magnification then
  1704.                                 trect.right := trunc(PicRect.right * magnification);
  1705.                             if trect.bottom > PicRect.bottom * magnification then
  1706.                                 trect.bottom := trunc(PicRect.bottom * magnification);
  1707.                             wrect := trect;
  1708.                             with SrcRect do begin
  1709.                                     ZoomCenterH := left + (wrect.right / 2.0) / magnification;
  1710.                                     ZoomCenterV := top + (wrect.bottom / 2.0) / magnification;
  1711.                                     width := wrect.right / magnification;
  1712.                                     height := wrect.bottom / magnification;
  1713.                                     left := round(ZoomCenterH - width / 2.0);
  1714.                                     if left < 0 then
  1715.                                         left := 0;
  1716.                                     if (left + width) > PicRect.right then
  1717.                                         left := round(PicRect.right - width);
  1718.                                     top := round(ZoomCenterV - height / 2.0);
  1719.                                     if top < 0 then
  1720.                                         top := 0;
  1721.                                     if (top + height) > PicRect.bottom then
  1722.                                         top := round(picRect.bottom - height);
  1723.                                     right := round(left + width);
  1724.                                     bottom := round(top + height);
  1725.                                     wrect.right := trunc((right - left) * magnification);
  1726.                                     wrect.bottom := trunc((bottom - top) * magnification);
  1727.                                 end;
  1728.                             savewrect := wrect;
  1729.                         end;
  1730.                     SizeWindow(WhichWindow, wrect.right, wrect.bottom, true);
  1731.                     WindowState := NormalWindow;
  1732.                     if WasDigitizing then
  1733.                         StartDigitizing;
  1734.                     exit(DoGrow)
  1735.                 end; {with info^}
  1736.         if WhichWindow = PlotWindow then begin
  1737.                 PlotWidth := LoWrd(NewSize);
  1738.                 PlotHeight := HiWrd(NewSize);
  1739.                 SetPort(PlotWindow);
  1740.                 SizeWindow(PlotWindow, PlotWidth, Plotheight, true);
  1741.                 InvalRect(PlotWindow^.PortRect);
  1742.                 exit(DoGrow)
  1743.             end;
  1744.         if (kind = TextKind) then begin
  1745.                 TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1746.                 GrowTextWindow(NewSize);
  1747.                 exit(DoGrow)
  1748.             end;
  1749.         if WhichWindow = ResultsWindow then begin
  1750.                 ResultsWidth := LoWrd(NewSize);
  1751.                 ResultsHeight := HiWrd(NewSize);
  1752.                 SetPort(ResultsWindow);
  1753.                 with ResultsWindow^.PortRect do
  1754.                     SetRect(tRect, right - 12, bottom - 12, right, bottom);
  1755.                 EraseRect(trect); {Erase Grow Box}
  1756.                 SizeWindow(ResultsWindow, ResultsWidth, ResultsHeight, true);
  1757.                 MoveControl(hScrollBar, -1, ResultsHeight - ScrollBarWidth);
  1758.                 MoveControl(vScrollBar, ResultsWidth - ScrollBarWidth, -1);
  1759.                 SizeControl(hScrollBar, ResultsWidth - 13, ScrollBarWidth + 1);
  1760.                 SizeControl(vScrollBar, ScrollBarWidth + 1, ResultsHeight - 13);
  1761.                 InvalRect(ResultsWindow^.PortRect);
  1762.                 with ListTE^^.viewRect do begin
  1763.                         right := left + ResultsWidth - ScrollBarWidth - 4;
  1764.                         bottom := top + ResultsHeight - ScrollBarWidth;
  1765.                     end;
  1766.                 UpdateResultsScrollBars;
  1767.                 ScrollResultsText;
  1768.             end;
  1769.     end;
  1770.  
  1771.  
  1772.     procedure ZoomIn; {(event: EventRecord)}
  1773.         var
  1774.             width, height, OldMagnification: extended;
  1775.             PicCenterH, PicCenterV, NewWidth, NewHeight: integer;
  1776.             trect: rect;
  1777.     begin
  1778.         if Info = NoInfo then begin
  1779.                 beep;
  1780.                 exit(ZoomIn)
  1781.             end;
  1782.         if Info^.ScaleToFitWindow then begin
  1783.                 PutError('The magnifying glass does not work in "Scale to Fit Window" mode.');
  1784.                 exit(ZoomIn)
  1785.             end;
  1786.         if BitAnd(Event.modifiers, OptionKey) = OptionKey then begin
  1787.                 ZoomOut;
  1788.                 WhatToUndo := NothingToUndo;
  1789.                 exit(ZoomIn)
  1790.             end;
  1791.         with Info^ do begin
  1792.                 OldMagnification := magnification;
  1793.                 if magnification = 1.0 then
  1794.                     magnification := 2.0
  1795.                 else if magnification = 2.0 then
  1796.                     magnification := 3.0
  1797.                 else if magnification = 3.0 then
  1798.                     magnification := 4.0
  1799.                 else begin
  1800.                         magnification := magnification * 2.0;
  1801.                         if magnification > 64.0 then begin
  1802.                                 magnification := 64.0;
  1803.                                 exit(ZoomIn)
  1804.                             end;
  1805.                     end;
  1806.                 if (WindowState = NormalWindow) and EqualRect(SrcRect, PicRect) then {Make window bigger?}
  1807.                     with trect do begin
  1808.                             NewWidth := trunc(PicRect.right * magnification);
  1809.                             NewHeight := trunc(PicRect.bottom * magnification);
  1810.                             if NewWidth <= 640 then begin
  1811.                                     GetWindowRect(wptr, trect);
  1812.                                     if ((left + NewWidth) <= ScreenWidth) and ((top + NewHeight) <= ScreenHeight) then begin
  1813.                                             SizeWindow(wptr, NewWidth, NewHeight, true);
  1814.                                             wrect.right := NewWidth;
  1815.                                             wrect.bottom := NewHeight;
  1816.                                         end;
  1817.                                 end;
  1818.                         end;
  1819.             end; {with}
  1820.         with Info^.SrcRect, Info^ do begin
  1821.                 PicCenterH := left + round(event.where.h / OldMagnification);
  1822.                 PicCenterV := top + round(event.where.v / OldMagnification);
  1823.                 width := wrect.right / magnification;
  1824.                 height := wrect.bottom / magnification;
  1825.                 left := PicCenterH - round(width / 2.0);
  1826.                 if left < 0 then
  1827.                     left := 0;
  1828.                 if (left + width) > PicRect.right then
  1829.                     left := PicRect.right - round(width);
  1830.                 top := PicCenterV - round(height / 2.0);
  1831.                 if top < 0 then
  1832.                     top := 0;
  1833.                 if (top + height) > PicRect.bottom then
  1834.                     top := picRect.bottom - round(height);
  1835.                 right := left + round(width);
  1836.                 bottom := top + round(height);
  1837.                 wrect.right := trunc((right - left) * magnification);
  1838.                 wrect.bottom := trunc((bottom - top) * magnification);
  1839.                 SizeWindow(wptr, wrect.right, wrect.bottom, true);
  1840.                 RoiShowing := false;
  1841.                 UpdatePicWindow;
  1842.                 DrawMyGrowIcon(wptr);
  1843.                 UpdateTitleBar;
  1844.                 WhatToUndo := UndoZoom;
  1845.                 ShowRoi;
  1846.             end; {with}
  1847.     end;
  1848.  
  1849.  
  1850.     procedure SynchScroll;
  1851.         var
  1852.             n: integer;
  1853.             TempInfo, SaveInfo: InfoPtr;
  1854.     begin
  1855.         SaveInfo := info;
  1856.         if allsamesize then
  1857.             for n := 1 to nPics do begin
  1858.                     TempInfo := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1859.                     TempInfo^.SrcRect := info^.SrcRect;
  1860.                     TempInfo^.magnification := Info^.magnification;
  1861.                     info := TempInfo;
  1862.                     UpdatePicWindow;
  1863.                     Info := SaveInfo;
  1864.                 end
  1865.         else
  1866.             PutError('Synchronized scrolling requires all images and all windows to be the same size.');
  1867.     end;
  1868.  
  1869.  
  1870.     procedure Scroll; {(event: EventRecord)}
  1871.         var
  1872.             hstart, vstart, DeltaH, DeltaV, width, height: integer;
  1873.             loc: point;
  1874.             SaveSR: rect;
  1875.             WasDigitizing: boolean;
  1876.     begin
  1877.         with info^ do begin
  1878.                 if ScaleToFitWindow then begin
  1879.                         PutError('Scrolling does not work in "Scale to Fit Window" mode.');
  1880.                         exit(Scroll)
  1881.                     end;
  1882.                 WasDigitizing := digitizing;
  1883.                 StopDigitizing;
  1884.                 with event.where do begin
  1885.                         hstart := h;
  1886.                         vstart := v
  1887.                     end;
  1888.                 with SrcRect do begin
  1889.                         width := right - left;
  1890.                         height := bottom - top
  1891.                     end;
  1892.                 SaveSR := SrcRect;
  1893.                 while StillDown do begin
  1894.                         GetMouse(loc);
  1895.                         DeltaH := hstart - loc.h;
  1896.                         DeltaV := vstart - loc.v;
  1897.                         with SrcRect do begin
  1898.                                 left := SaveSR.left + DeltaH;
  1899.                                 if left < 0 then
  1900.                                     left := 0;
  1901.                                 if (left + width) > PicRect.right then
  1902.                                     left := PicRect.right - width;
  1903.                                 right := left + width;
  1904.                                 top := SaveSR.top + DeltaV;
  1905.                                 if top < 0 then
  1906.                                     top := 0;
  1907.                                 if (top + height) > PicRect.bottom then
  1908.                                     top := PicRect.bottom - height;
  1909.                                 bottom := top + height;
  1910.                             end;
  1911.                         UpdatePicWindow;
  1912.                         DrawMyGrowIcon(wptr);
  1913.                     end;
  1914.                 WhatToUndo := NothingToUndo;
  1915.                 ShowRoi;
  1916.                 if OptionKeyDown and (nPics > 1) then
  1917.                     SynchScroll;
  1918.                 if WasDigitizing then
  1919.                     StartDigitizing;
  1920.             end; {with info^}
  1921.     end;
  1922.  
  1923.  
  1924.     procedure ConverToSystemClipboard;
  1925.     {Converts local clipboard to system-wide clipboard}
  1926.     {when quitting or switching to other programs.}
  1927.     var
  1928.         PicH: PicHandle;
  1929.         err: LongInt;
  1930.         saveClipRgn: RgnHandle;
  1931.     begin
  1932.         PicH := nil;
  1933.         if ((WhatsOnClip = RectPic) or (WhatsOnClip = CameraPic)) and (ClipBuf <> nil) and not ClipboardConverted then
  1934.             with ClipBufInfo^ do begin
  1935.                 ShowWatch;
  1936.                 SetPort(GrafPtr(osPort));
  1937.                 saveClipRgn := NewRgn;
  1938.                 GetClip(saveClipRgn);
  1939.                 ClipRect(RoiRect);
  1940.                 LoadLUT(ctable);  {Switch to original LUT}
  1941.                 RGBForeColor(BlackRGB);
  1942.                 RGBBackColor(WhiteRGB);
  1943.                 PicH := OpenPicture(RoiRect);
  1944.                 with osPort^ do
  1945.                     CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, RoiRect, RoiRect, SrcCopy, nil);
  1946.                 ClosePicture;
  1947.                 if info <> NoInfo then
  1948.                     LoadLUT(info^.ctable); {Restore LUT}
  1949.                 if (PicH <> nil) or ClipTextInBuffer then begin
  1950.                         err := ZeroScrap;
  1951.                         if err = NoErr then begin
  1952.                             if PicH <> nil then begin
  1953.                                 hlock(handle(PicH));
  1954.                                 err := PutScrap(GetHandleSize(handle(PicH)), 'PICT', handle(PicH)^);
  1955.                                 hunlock(handle(PicH));
  1956.                                 DisposeHandle(handle(PicH));
  1957.                             end;
  1958.                             if (err = noErr) and ClipTextInBuffer then
  1959.                                 err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  1960.                         end; {if err=NoErr}
  1961.                     end;
  1962.                 ClipboardConverted := true;
  1963.                 SetClip(saveClipRgn);
  1964.                 DisposeRgn(saveClipRgn);
  1965.             end; {with}
  1966.     end;
  1967.  
  1968.  
  1969.     procedure SetupOperation; {(item: integer)}
  1970.         var
  1971.             AutoSelectAll: boolean;
  1972.     begin
  1973.         if NotinBounds then
  1974.             exit(SetupOperation);
  1975.         if item = DrawBoundaryItem then
  1976.             if NoSelection then
  1977.                 exit(SetupOperation);
  1978.         if item = InvertItem then
  1979.             if not CheckCalibration then
  1980.                 exit(SetupOperation);
  1981.         StopDigitizing;
  1982.         AutoSelectAll := not Info^.RoiShowing;
  1983.         if AutoSelectAll then
  1984.             SelectAll(true);
  1985.         SetupUndo;
  1986.         WhatToUndo := UndoEdit;
  1987.         case Item of
  1988.             FillItem:  begin
  1989.                     CurrentOp := PaintOp;
  1990.                     OpPending := true
  1991.                 end;
  1992.             InvertItem:  begin
  1993.                     CurrentOp := InvertOp;
  1994.                     OpPending := true
  1995.                 end;
  1996.             DrawBoundaryItem:  begin
  1997.                     CurrentOp := FrameOp;
  1998.                     OpPending := true
  1999.                 end;
  2000.         end;
  2001.         if AutoSelectAll then
  2002.             KillRoi;
  2003.         RoiUpdateTime := 0; {Forces outline to be redrawn in scale-to-fit mode.}
  2004.     end;
  2005.  
  2006.  
  2007.     procedure DoUndo;
  2008.         var
  2009.             aok: boolean;
  2010.     begin
  2011.         case WhatToUndo of
  2012.             UndoMeasurement: 
  2013.                 UndoLastMeasurement(true);
  2014.             UndoPoint:  begin
  2015.                     Undo;
  2016.                     UpdatePicWindow;
  2017.                     UndoLastMeasurement(true);
  2018.                     WhatToUndo := NothingToUndo;
  2019.                 end;
  2020.             UndoZoom:  begin
  2021.                     ZoomOut;
  2022.                     if info^.magnification < 2 then
  2023.                         WhatToUndo := NothingToUndo;
  2024.                 end;
  2025.             UndoOutLine:  begin
  2026.                     undo;
  2027.                     if WandAutoMeasure then
  2028.                         UndoLastMeasurement(true);
  2029.                     WhatToUndo := NothingToUndo;
  2030.                     UpdatePicWindow;
  2031.                 end;
  2032.             UndoSliceDelete, UndoFirstSliceDelete: 
  2033.                 if info^.StackInfo <> nil then
  2034.                     with info^.StackInfo^ do begin
  2035.                             if WhatToUndo = UndoFirstSliceDelete then
  2036.                                 CurrentSlice := 0;
  2037.                             aok := AddSlice(false);
  2038.                             if aok then begin
  2039.                                     Undo;
  2040.                                     UpdatePicWindow;
  2041.                                 end
  2042.                             else if CurrentSlice = 0 then
  2043.                                 CurrentSlice := 1;
  2044.                         end;
  2045.             UndoLUT:  begin
  2046.                     UndoLutChange;
  2047.                     DrawMap;
  2048.                     DensitySlicing := false;
  2049.                 end;
  2050.             otherwise begin
  2051.                     if UndoFromClip then
  2052.                         OpPending := false;
  2053.                     if not OpPending then
  2054.                         undo;
  2055.                     WhatToUndo := NothingToUndo;
  2056.                     if IsInsertionPoint then begin
  2057.                             InsertionPoint := TextStart;
  2058.                             TextStr := '';
  2059.                         end;
  2060.                     UpdatePicWindow;
  2061.                     if OpPending and (CurrentOp = PasteOp) then begin
  2062.                             OpPending := false;
  2063.                             KillRoi;
  2064.                         end;
  2065.                     OpPending := false;
  2066.                 end;
  2067.         end; {case}
  2068.     end;
  2069.  
  2070.  
  2071.  
  2072. end.